home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / advanced97 / VOLUME.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  15.2 KB  |  657 lines

  1. #include <GL/glut.h>
  2. #include <math.h>
  3. #include "texture.h"
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7.  
  8. /* nonzero if not power of 2 */ 
  9. #define NOTPOW2(num) ((num) & (num - 1))
  10.  
  11. int
  12. makepow2(int val)
  13. {
  14.     int power = 0;
  15.     if(!val)
  16.     return 0;
  17.  
  18.     while(val >>= 1)
  19.     power++;
  20.  
  21.     return(1 << power);
  22. }
  23.  
  24. #define CHECK_ERROR(str)                                           \
  25. {                                                                  \
  26.     GLenum error;                                                  \
  27.     if(error = glGetError())                                       \
  28.        printf("GL Error: %s (%s)\n", gluErrorString(error), str);  \
  29. }
  30.  
  31. enum {X, Y, Z, W};
  32. enum {R, G, B, A};
  33. enum {OVER, ATTENUATE, NONE, LASTOP}; /* blend modes */
  34. /* mouse modes */
  35. enum {OBJ_ANGLE, SLICES, CUTTING, GEOMXY, GEOMZ, MINBOOST, BOOSTWID, BOOST}; 
  36. enum {NOLIST, SPHERE}; /* display list */
  37.  
  38. /* window dimensions */
  39. int winWidth = 512;
  40. int winHeight = 512;
  41. int active;
  42. int operator = OVER;
  43. GLboolean texture = GL_TRUE;
  44. GLboolean dblbuf = GL_TRUE;
  45. GLboolean cut = GL_FALSE;
  46. GLboolean geom = GL_FALSE;
  47. GLboolean map = GL_FALSE;
  48. GLint cutbias = 50;
  49. int hasBlendColor = 0;
  50.  
  51. GLfloat objangle[2] = {0.f, 0.f};
  52. GLfloat objpos[3] = {0.f, 0.f, 0.f};
  53.  
  54.  
  55. GLfloat minboost = 0.f, boostwid = .03f, boost = 3.f; /* transfer function */
  56.  
  57. /* 3d texture data that's read in */
  58. /* XXX TODO; make command line arguments */
  59. int Texwid = 128; /* dimensions of each 2D texture */
  60. int Texht = 128;
  61. int Texdepth = 69; /* number of 2D textures */
  62.  
  63. /* Actual dimensions of the texture (restricted to max 3d texture size) */
  64. int texwid, texht, texdepth;
  65. int slices;
  66. GLubyte *tex3ddata; /* pointer to 3D texture data */
  67.  
  68.  
  69. GLfloat *lighttex = 0;
  70. GLfloat lightpos[4] = {0.f, 0.f, 1.f, 0.f};
  71. GLboolean lightchanged[2] = {GL_TRUE, GL_TRUE};
  72.  
  73.  
  74. void
  75. reshape(int wid, int ht)
  76. {
  77.     winWidth = wid;
  78.     winHeight = ht;
  79.     glViewport(0, 0, wid, ht);
  80. }
  81.  
  82.  
  83. void
  84. motion(int x, int y)
  85. {
  86.     switch(active)
  87.     {
  88.     case OBJ_ANGLE:
  89.     objangle[X] = (x - winWidth/2) * 360./winWidth;
  90.     objangle[Y] = (y - winHeight/2) * 360./winHeight;
  91.     glutPostRedisplay();
  92.     break;
  93.     case SLICES:
  94.     slices = x * texwid/winWidth;
  95.     glutPostRedisplay();
  96.     break;
  97.     case CUTTING:
  98.     cutbias = (x - winWidth/2) * 300/winWidth;
  99.     glutPostRedisplay();
  100.     break;
  101.     case GEOMXY:
  102.     objpos[X] = (x - winWidth/2) * 300/winWidth;
  103.     objpos[Y] = (winHeight/2 - y) * 300/winHeight;
  104.     glutPostRedisplay();
  105.     break;
  106.     case GEOMZ:
  107.     objpos[Z] = (x - winWidth/2) * 300/winWidth;
  108.     glutPostRedisplay();
  109.     break;
  110.     case MINBOOST:
  111.     minboost = x * .25f/winWidth;
  112.     glutPostRedisplay();
  113.     break;
  114.     case BOOSTWID:
  115.     boostwid = x * .5f/winWidth;
  116.     glutPostRedisplay();
  117.     break;
  118.     case BOOST:
  119.     boost = x * 20.f/winWidth;
  120.     glutPostRedisplay();
  121.     break;
  122.     }
  123. }
  124.  
  125. void
  126. mouse(int button, int state, int x, int y)
  127. {
  128.     if(state == GLUT_DOWN)
  129.     switch(button)
  130.     {
  131.     case GLUT_LEFT_BUTTON: /* rotate the data volume */
  132.         if(map)
  133.         active = MINBOOST;
  134.         else
  135.         active = OBJ_ANGLE;
  136.         motion(x, y);
  137.         break;
  138.     case GLUT_MIDDLE_BUTTON:
  139.         if(map)
  140.         active = BOOSTWID;
  141.         else
  142.         if(cut)
  143.             active = CUTTING; /* move cutting plane */
  144.         else
  145.             active = GEOMXY; /* move geometry */
  146.         motion(x, y);
  147.         break;
  148.     case GLUT_RIGHT_BUTTON: /* move the polygon */
  149.         if(map)
  150.         active = BOOST;
  151.         else
  152.         if(geom)
  153.             active = GEOMZ;
  154.         else
  155.             active = SLICES;
  156.         motion(x, y);
  157.         break;
  158.     }
  159. }
  160.  
  161. /* use pixel path to remap 3D texture data */
  162. void
  163. remaptex(void)
  164. {
  165.     int i, size;
  166.     GLfloat *map;
  167.  
  168.     glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
  169.  
  170.     glGetIntegerv(GL_MAX_PIXEL_MAP_TABLE, &size);
  171.  
  172.     map = (GLfloat *)malloc(sizeof(GLfloat) * size);
  173.     for(i = 0; i < size;i++)
  174.     {
  175.     map[i] = (GLfloat)i/(size - 1);
  176.     if(((GLfloat)i/size > minboost) &&
  177.        ((GLfloat)i/size < minboost + boostwid))
  178.     {
  179.         map[i] *= boost;
  180.     }
  181.     else
  182.         map[i] /= boost;
  183.     }
  184.  
  185.     glPixelMapfv(GL_PIXEL_MAP_R_TO_R, size, map);
  186.     glPixelMapfv(GL_PIXEL_MAP_G_TO_G, size, map);
  187.     glPixelMapfv(GL_PIXEL_MAP_B_TO_B, size, map);
  188.     glPixelMapfv(GL_PIXEL_MAP_A_TO_A, size, map);
  189.  
  190. #ifdef GL_EXT_texture3D
  191.     glTexImage3DEXT(GL_TEXTURE_3D_EXT, 0, GL_LUMINANCE_ALPHA,
  192.             texwid, texht, texdepth,
  193.             0,
  194.             GL_RGBA, GL_UNSIGNED_BYTE, tex3ddata);
  195. #endif
  196.  
  197.     glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
  198.     free(map);
  199.  
  200.     CHECK_ERROR("OpenGL Error in remaptex()");
  201. }
  202.  
  203.  
  204. GLdouble clipplane0[] = {-1.,  0.,  0., 100.}; /* x < 100 out */
  205. GLdouble clipplane1[] = { 1.,  0.,  0., 100.}; /* x > 100 out */
  206. GLdouble clipplane2[] = { 0., -1.,  0., 100.}; /* y < 100 out */
  207. GLdouble clipplane3[] = { 0.,  1.,  0., 100.}; /* y > 100 out */
  208. GLdouble clipplane4[] = { 0.,  0., -1., 100.}; /* z < 100 out */
  209. GLdouble clipplane5[] = { 0.,  0.,  1., 100.}; /* z > 100 out */
  210.  
  211. /* define a cutting plane */
  212. GLdouble cutplane[] = {0.f, -.5f, -2.f, 50.f};
  213.  
  214. /* draw the object unlit without surface texture */
  215. void redraw(void)
  216. {
  217.     int i;
  218.     GLfloat offS, offT, offR; /* mapping texture to planes */
  219.  
  220.     offS = 200.f/texwid;
  221.     offT = 200.f/texht;
  222.     offR = 200.f/texdepth;
  223.     
  224.     clipplane0[W] = 100.f - offS;
  225.     clipplane1[W] = 100.f - offS;
  226.     clipplane2[W] = 100.f - offT;
  227.     clipplane3[W] = 100.f - offT;
  228.     clipplane4[W] = 100.f - offR;
  229.     clipplane5[W] = 100.f - offR;
  230.  
  231.     glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  232.  
  233.     if(map)
  234.     remaptex();
  235.  
  236.     /* GL_MODELVIEW */
  237.     if(cut)
  238.     {
  239.     cutplane[W] = cutbias;
  240.     glClipPlane(GL_CLIP_PLANE5, cutplane);
  241.     }
  242.  
  243.     glPushMatrix(); /* identity */
  244.     glRotatef(objangle[X], 0.f, 1.f, 0.f);
  245.     glRotatef(objangle[Y], 1.f, 0.f, 0.f);
  246.     glClipPlane(GL_CLIP_PLANE0, clipplane0);
  247.     glClipPlane(GL_CLIP_PLANE1, clipplane1);
  248.     glClipPlane(GL_CLIP_PLANE2, clipplane2);
  249.     glClipPlane(GL_CLIP_PLANE3, clipplane3);
  250.     glClipPlane(GL_CLIP_PLANE4, clipplane4);
  251.     if(!cut)
  252.     glClipPlane(GL_CLIP_PLANE5, clipplane5);
  253.     glPopMatrix(); /* back to identity */
  254.  
  255.     /* draw opaque geometry here */
  256.     glDisable(GL_CLIP_PLANE0);
  257.     glDisable(GL_CLIP_PLANE1);
  258.     glDisable(GL_CLIP_PLANE2);
  259.     glDisable(GL_CLIP_PLANE3);
  260.     glDisable(GL_CLIP_PLANE4);
  261.     if(geom)
  262.     {
  263.     if(!cut)
  264.         glDisable(GL_CLIP_PLANE5);
  265.     glPushMatrix();
  266.     glTranslatef(objpos[X], objpos[Y], objpos[Z]);
  267.     glCallList(SPHERE);
  268.     glPopMatrix();
  269.     }
  270.     glMatrixMode(GL_TEXTURE);
  271.     glEnable(GL_CLIP_PLANE0);
  272.     glEnable(GL_CLIP_PLANE1);
  273.     glEnable(GL_CLIP_PLANE2);
  274.     glEnable(GL_CLIP_PLANE3);
  275.     glEnable(GL_CLIP_PLANE4);
  276.     glEnable(GL_CLIP_PLANE5);
  277.  
  278.     glMatrixMode(GL_TEXTURE);
  279.     glPushMatrix(); /* identity */
  280.     glTranslatef( .5f,  .5f, .5f);
  281.     glRotatef(objangle[Y], 1.f, 0.f, 0.f);
  282.     glRotatef(objangle[X], 0.f, 0.f, 1.f);
  283.     glTranslatef( -.5f,  -.5f, -.5f);
  284.  
  285.     switch(operator)
  286.     {
  287.     case OVER:
  288.     glEnable(GL_BLEND);
  289.     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  290.     break;
  291.     case ATTENUATE:
  292. #ifdef GL_EXT_blend_color
  293.         if (hasBlendColor){
  294.         glEnable(GL_BLEND);
  295.         glBlendFunc(GL_CONSTANT_ALPHA_EXT, GL_ONE);
  296.         glBlendColorEXT(1.f, 1.f, 1.f, 1.f/slices);
  297.         } else
  298. #endif
  299.         {
  300.             fprintf(stderr, "volume: attenuate not supported!\n");
  301.         }
  302.         break;
  303.     case NONE:
  304.     /* don't blend */
  305.     break;
  306.     }
  307.  
  308.     if(texture) {
  309. #ifdef GL_EXT_texture3D
  310.        glEnable(GL_TEXTURE_3D_EXT);
  311. #endif
  312.     } else {
  313. #ifdef GL_EXT_texture3D
  314.        glDisable(GL_TEXTURE_3D_EXT);
  315. #endif
  316.        glEnable(GL_LIGHTING);
  317.        glEnable(GL_LIGHT0);
  318.     }
  319.  
  320.     
  321.  
  322.     for(i = 0; i < slices; i++)
  323.     {
  324.     glBegin(GL_QUADS);
  325.     glVertex3f(-100.f, -100.f, 
  326.            -100.f + offR + i * (200.f - 2 * offR)/(slices - 1));
  327.     glVertex3f( 100.f, -100.f,
  328.            -100.f + offR + i * (200.f - 2 * offR)/(slices - 1));
  329.     glVertex3f( 100.f,  100.f,
  330.            -100.f + offR + i * (200.f - 2 * offR)/(slices - 1));
  331.     glVertex3f(-100.f,  100.f,
  332.            -100.f + offR + i * (200.f - 2 * offR)/(slices - 1));
  333.     glEnd();
  334.     }
  335. #ifdef GL_EXT_texture3D
  336.     glDisable(GL_TEXTURE_3D_EXT);
  337. #endif
  338.     if(!texture)
  339.     {
  340.        glDisable(GL_LIGHTING);
  341.     }
  342.     glDisable(GL_BLEND);
  343.  
  344.     glPopMatrix(); /* back to identity */
  345.     glMatrixMode(GL_MODELVIEW);
  346.  
  347.     if(operator == ATTENUATE)
  348.     {
  349.     glPixelTransferf(GL_RED_SCALE, 3.f); /* brighten image */
  350.     glPixelTransferf(GL_GREEN_SCALE, 3.f);
  351.     glPixelTransferf(GL_BLUE_SCALE, 3.f);
  352.     glCopyPixels(0, 0, winWidth, winHeight, GL_COLOR);
  353.     }
  354.     if(dblbuf)
  355.     glutSwapBuffers(); 
  356.     else
  357.     glFlush(); 
  358.  
  359.     CHECK_ERROR("OpenGL Error in redraw()");
  360. }
  361.  
  362. /* ARGSUSED1 */
  363. void key(unsigned char key, int x, int y)
  364. {
  365.     switch(key)
  366.     {
  367.     case 'm': /* remap texture values */
  368.     if(map)
  369.     {
  370.         fprintf(stderr, "remapping off\n");
  371.         map = GL_FALSE;
  372.     }
  373.     else
  374.     {
  375.         fprintf(stderr, "remapping on:\n"
  376.                     "left mouse moves emphasize value\n"
  377.                     "middle mouse moves emphasize width\n"
  378.                     "right mouse adjusts gain\n");
  379.         map = GL_TRUE;
  380.     }
  381.  
  382.     remaptex();
  383.     glutPostRedisplay();
  384.     break;
  385.     case 'o':
  386.     operator++;
  387.     if(operator == LASTOP)
  388.         operator = OVER;
  389.     glutPostRedisplay();
  390.     break;
  391.     case 't':
  392.     if(texture)
  393.         texture = GL_FALSE;
  394.     else
  395.         texture = GL_TRUE;
  396.     glutPostRedisplay();
  397.     break;
  398.     case 'c':
  399.     if(cut)
  400.     {
  401.         fprintf(stderr, "cutting plane off\n");
  402.         cut = GL_FALSE;
  403.     }
  404.     else
  405.     {
  406.         fprintf(stderr, 
  407.             "Cutting plane on: "
  408.             "middle mouse (horizontal) moves cutting plane\n");
  409.         cut = GL_TRUE;
  410.     }
  411.     glutPostRedisplay();
  412.     break;
  413.     case 'g': /* toggle geometry */
  414.     if(geom)
  415.         geom = GL_FALSE;
  416.     else
  417.         geom = GL_TRUE;
  418.     glutPostRedisplay();
  419.     break;
  420.     case '\033':
  421.     exit(0);
  422.     break;
  423.     case '?':
  424.     case 'h':
  425.     default:
  426.     fprintf(stderr, 
  427.         "Keyboard Commands\n"
  428.         "m - toggle transfer function (remapping)\n"
  429.         "o - toggle operator\n"
  430.         "t - toggle 3D texturing\n"
  431.         "c - toggle cutting plane\n"
  432.         "g - toggle geometry\n");
  433.     break;
  434.     }
  435. }
  436.  
  437. GLubyte *
  438. loadtex3d(int *texwid, int *texht, int *texdepth, int *texcomps)
  439. {
  440.     char *filename;
  441.     GLubyte *tex3ddata;
  442.     GLuint *texslice; /* 2D slice of 3D texture */
  443.     GLint max3dtexdims; /* maximum allowed 3d texture dimension */
  444.     GLint newval;
  445.     int i;
  446.  
  447.     /* load 3D texture data */
  448.     filename = (char*)malloc(sizeof(char) * strlen("data/skull/skullXX.la"));
  449.  
  450.     tex3ddata = (GLubyte *)malloc(Texwid * Texht * Texdepth * 
  451.                   4 * sizeof(GLubyte));
  452.     for(i = 0; i < Texdepth; i++)
  453.     {
  454.     sprintf(filename, "data/skull/skull%d.la", i);
  455.     /* read_texture reads as RGBA */
  456.     texslice = read_texture(filename, texwid, texht, texcomps);
  457.     memcpy(&tex3ddata[i * Texwid * Texht * 4],  /* copy in a slice */
  458.            texslice, 
  459.            Texwid * Texht * 4 * sizeof(GLubyte));
  460.     free(texslice);
  461.     }
  462.     free(filename);
  463.  
  464.     *texdepth = Texdepth;
  465.  
  466.     max3dtexdims = 0;
  467. #ifdef GL_EXT_texture3D
  468.     glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE_EXT, &max3dtexdims);
  469. #endif
  470.  
  471.     /* adjust width */
  472.     newval = *texwid;
  473.     if(*texwid > max3dtexdims)
  474.     newval = max3dtexdims;
  475.     if(NOTPOW2(*texwid))
  476.         newval = makepow2(*texwid);
  477.     if(newval != *texwid)
  478.     {
  479.     glPixelStorei(GL_UNPACK_ROW_LENGTH, *texwid);
  480.     glPixelStorei(GL_UNPACK_SKIP_PIXELS, (*texwid - newval)/2);
  481.     *texwid = newval;
  482.     }
  483.  
  484.     /* adjust height */
  485.     newval = *texht;
  486.     if(*texht > max3dtexdims)
  487.     newval = max3dtexdims;
  488.     if(NOTPOW2(*texht))
  489.         newval = makepow2(*texht);
  490.     if(*texht > newval)
  491.     {
  492. #ifdef GL_EXT_texture3D
  493.     glPixelStorei(GL_UNPACK_IMAGE_HEIGHT_EXT, *texht);
  494. #endif
  495.     glPixelStorei(GL_UNPACK_SKIP_ROWS, (*texht - newval)/2);
  496.     *texht = newval;
  497.     }
  498.  
  499.     /* adjust depth */
  500.     newval = *texdepth;
  501.     if(*texdepth > max3dtexdims)
  502.     newval = max3dtexdims;
  503.     if(NOTPOW2(*texdepth))
  504.         newval = makepow2(*texdepth);
  505.     if(*texdepth > newval)
  506.     {
  507.     *texdepth = newval;
  508.     }
  509.     return tex3ddata;
  510. }
  511.  
  512.  
  513.  
  514. main(int argc, char *argv[])
  515. {
  516.     int texcomps;
  517.     static GLfloat splane[4] = {1.f/200.f, 0.f, 0.f, .5f};
  518.     static GLfloat rplane[4] = {0, 1.f/200.f, 0, .5f};
  519.     static GLfloat tplane[4] = {0, 0, 1.f/200.f, .5f};
  520.     static GLfloat lightpos[4] = {150., 150., 150., 1.f};
  521.  
  522.  
  523.     glutInit(&argc, argv);
  524.     glutInitWindowSize(winWidth, winHeight);
  525.     if(argc > 1)
  526.     {
  527.     char *args = argv[1];
  528.     GLboolean done = GL_FALSE;
  529.     while(!done)
  530.     {
  531.         switch(*args)
  532.         {
  533.         case 's': /* single buffer */
  534.         printf("Single Buffered\n");
  535.         dblbuf = GL_FALSE;
  536.         break;
  537.         case '-': /* do nothing */
  538.         break;
  539.         case 0:
  540.         done = GL_TRUE;
  541.         break;
  542.         }
  543.         args++;
  544.     }
  545.     }
  546.     if(dblbuf)
  547.     glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE);
  548.     else
  549.     glutInitDisplayMode(GLUT_RGBA|GLUT_DEPTH);
  550.  
  551.     (void)glutCreateWindow("volume rendering demo");
  552.     glutDisplayFunc(redraw);
  553.     glutReshapeFunc(reshape);
  554.     glutMouseFunc(mouse);
  555.     glutMotionFunc(motion);
  556.     glutKeyboardFunc(key);
  557.  
  558.     /* Initialize OpenGL State */
  559.  
  560.     /* draw a perspective scene */
  561. #if 0
  562.     glMatrixMode(GL_PROJECTION);
  563.     /* cube, 300 on a side */
  564.     glFrustum(-150., 150., -150., 150., 300., 600.);
  565.     glMatrixMode(GL_MODELVIEW);
  566.     /* look at scene from (0, 0, 450) */
  567.     gluLookAt(0., 0., 450., 0., 0., 0., 0., 1., 0.);
  568. #else
  569.     glMatrixMode(GL_PROJECTION);
  570.     /* cube, 300 on a side */
  571.     glOrtho(-150., 150., -150., 150., -150., 150.);
  572.     glMatrixMode(GL_MODELVIEW);
  573. #endif
  574.  
  575.     glEnable(GL_DEPTH_TEST);
  576. #ifdef GL_EXT_texture3D
  577.     glEnable(GL_TEXTURE_3D_EXT);
  578. #endif
  579.  
  580.     glEnable(GL_TEXTURE_GEN_S);
  581.     glEnable(GL_TEXTURE_GEN_T);
  582.     glEnable(GL_TEXTURE_GEN_R);
  583.  
  584.     glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  585.     glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  586.     glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  587.  
  588.     glTexGenfv(GL_S, GL_OBJECT_PLANE, splane);
  589.     glTexGenfv(GL_T, GL_OBJECT_PLANE, tplane);
  590.     glTexGenfv(GL_R, GL_OBJECT_PLANE, rplane);
  591.  
  592. #ifdef GL_EXT_texture3D
  593.     /* to avoid boundary problems */
  594.     glTexParameteri(GL_TEXTURE_3D_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP);
  595.     glTexParameteri(GL_TEXTURE_3D_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP);
  596.     glTexParameteri(GL_TEXTURE_3D_EXT, GL_TEXTURE_WRAP_R_EXT, GL_CLAMP);
  597. #endif
  598.  
  599.     glEnable(GL_CLIP_PLANE0);
  600.     glEnable(GL_CLIP_PLANE1);
  601.     glEnable(GL_CLIP_PLANE2);
  602.     glEnable(GL_CLIP_PLANE3);
  603.     glEnable(GL_CLIP_PLANE4);
  604.     glEnable(GL_CLIP_PLANE5);
  605.  
  606.     glDisable(GL_LIGHT0);
  607.     glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  608.  
  609.  
  610.  
  611.     tex3ddata = loadtex3d(&texwid, &texht, &texdepth, &texcomps);
  612.  
  613.     slices = texht;
  614.  
  615. #ifdef GL_EXT_texture3D
  616.     glTexParameteri(GL_TEXTURE_3D_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  617.     glTexImage3DEXT(GL_TEXTURE_3D_EXT, 0, GL_LUMINANCE_ALPHA,
  618.             texwid, texht, texdepth,
  619.             0,
  620.             GL_RGBA, GL_UNSIGNED_BYTE, tex3ddata);
  621. #endif
  622.  
  623.     /* make a display list containing a sphere */
  624.     glNewList(SPHERE, GL_COMPILE);
  625.     {
  626.     static GLfloat lightpos[] = {150.f, 150.f, 150.f, 1.f};
  627.     static GLfloat material[] = {1.f, .5f, 1.f, 1.f};
  628.     GLUquadricObj *qobj = gluNewQuadric();
  629.     glPushAttrib(GL_LIGHTING_BIT);
  630.     glEnable(GL_LIGHTING);
  631.     glEnable(GL_LIGHT0);
  632.     glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
  633.     glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, material);
  634.     gluSphere(qobj, 20.f, 20, 20);
  635.     gluDeleteQuadric(qobj);
  636.     glPopAttrib();
  637.     }
  638.     glEndList();
  639.  
  640.     key('?', 0, 0); /* print usage message */
  641.  
  642.     CHECK_ERROR("end of main");
  643.  
  644.     if(!glutExtensionSupported("GL_EXT_texture3d")) {
  645.       fprintf(stderr,
  646.         "volume: requires OpenGL texture 3D extension to operate correctly.\n");
  647.     }
  648.     hasBlendColor = glutExtensionSupported("GL_EXT_blend_color");
  649.     if(!hasBlendColor) {
  650.       fprintf(stderr,
  651.         "volume: needs OpenGL blend color extension to attenuate.\n");
  652.     }
  653.  
  654.     glutMainLoop();
  655.     return 0;             /* ANSI C requires main to return int. */
  656. }
  657.